﻿using RockBus.Logging.Interfaces;
using RockBus.Messages.Interfaces;
using RockBus.Queueing.Interfaces;
using RockBus.Routing.Interfaces;
using System;

namespace RockBus.Routing
{
    public class QueueManager : IQueueManager
    {
        private const string ProcessingQueueCounterName = "Routing.Queue.Processing";
        private const string RetryQueueCounterName = "Routing.RetryQueue.Processing";
        private const string ErrorQueueCounterName = "Routing.ErrorQueue.Processing";

        public QueueManager(
            ILogger logger,
            IQueueFactory queueFactory
            )
        {
            this.QueueFactory = queueFactory;
        }

        private ILogger Logger { get; set; }

        private IQueueFactory QueueFactory { get; set; }

        private IQueue<IMessageContext> MessageQueue { get; set; }

        private IQueue<IMessageContext> ExceptionQueue { get; set; }

        private IQueue<IMessageContext> RetryQueue { get; set; }

        /// <summary>
        /// Registers dequeue actions and internally updates a performance counter pertaining to the queue used
        /// </summary>
        /// <param name="dequeueMessageAction">Dequeue action for a processing message queue</param>
        /// <param name="dequeueExceptionAction">Dequeue action for an exception message queue</param>
        /// <param name="dequeueRetryAction">Dequeue action for a retry message queue</param>
        public void Register(Action<IMessageContext> dequeueMessageAction, Action<IMessageContext> dequeueExceptionAction, Action<IMessageContext> dequeueRetryAction)
        {
            this.MessageQueue = this.QueueFactory.CreateQueue<IMessageContext>(ProcessingQueueCounterName, (t) => { dequeueMessageAction(t); });
            this.ExceptionQueue = this.QueueFactory.CreateQueue<IMessageContext>(ErrorQueueCounterName, (t) => { dequeueExceptionAction(t); });
            this.RetryQueue = this.QueueFactory.CreateQueue<IMessageContext>(RetryQueueCounterName, (t) => { dequeueRetryAction(t); });
        }

        public void ProcessMessage(IMessageContext messageContext)
        {
            if (this.MessageQueue == null)
            {
                throw new InvalidOperationException("MessageQueue has not been created yet.");
            }

            this.MessageQueue.Enqueue(messageContext);
        }

        public void ProcessException(IMessageContext messageContext)
        {
            if (this.ExceptionQueue == null)
            {
                throw new InvalidOperationException("ExceptionQueue has not been created yet.");
            }

            this.ExceptionQueue.Enqueue(messageContext);
        }

        public void ProcessRetry(IMessageContext messageContext)
        {
            if (this.RetryQueue == null)
            {
                throw new InvalidOperationException("RetryQueue has not been created yet.");
            }

            this.RetryQueue.Enqueue(messageContext);
        }

    }
}